`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/15 18:13:29
// Design Name: 
// Module Name: ControlUnit
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
`include"Parameters.v"
import Params::*;

module ControlUnit(
input logic [6:0] Op,
input logic [2:0] Fn3,
input logic [6:0] Fn7,
output logic JalD,                      //是否为Jal指令
output logic JalrD,                     //是否是Jalr指令
output LoadType RegWriteD,              //LOAD指令字节选取(LW,LH,LB,...)
output logic MemToRegD,                 //写入寄存器的值是否来自MEM
output logic [3:0] MemWriteD,           //写MEM时字节选中信号，S类型指令
output logic LoadNpcD,                  //MEM阶段是否计算PC+4,用于Jal和Jalr指令
output BType BranchTypeD,          //分支指令类型，BEQ,BNE,...
output AluOp AluControlD,          //EXE阶段ALU控制信号，进行何种运算
output logic [1:0] AluSrc2D,             //第二个源操作数的来源
output logic AluSrc1D,                   //第一个源操作数的来源，rs1或者pc
output Type ImmType               //立即数类型，不同类型解析不同
    );

//jal,jalr
assign JalD=(Op==7'b1101111)?1'b1:1'b0;                   //是否为Jal指令
assign JalrD=(Op==7'b1100111)?1'b1:1'b0;                  //是否为jalr指令
//RegWriteD
always_comb
begin
    if(Op==7'b0000011)                    //是load指令
    begin
        case(Fn3)
            3'b000:RegWriteD=LB; //LB
            3'b001:RegWriteD=LH; //LH
            3'b010:RegWriteD=LW; //LW
            3'b100:RegWriteD=LBU; //LBU
            3'b101:RegWriteD=LHU; //LHU
            default:RegWriteD=NOREGWRITE;                        //出错,不写寄存器
        endcase
    end
    else if(Op==7'b0010011||Op==7'b0110011||Op==7'b0110111||Op==7'b0010111||Op==7'b1101111||Op==7'b1100111)
    begin
        RegWriteD=LW;             //I型指令(寄存器-立即数指令)、R型指令、U型指令(LUI,AUIPC),J型指令(JAL)和JALR指令，写寄存器
    end
    else                           //B型，S型指令，不写寄存器
    begin
        RegWriteD=NOREGWRITE;
    end
end
//MemToRegD
always_comb
begin
    if(Op==7'b0000011)           //是load指令
        MemToRegD=1;
    else                         //其他指令数据均不来自于MEM
        MemToRegD=0;           
end
//MemWriteD
always_comb
begin
    if(Op==7'b0100011)             //S型指令，写MEM
        case(Fn3)
           3'b000:MemWriteD=4'b0001;    //SB
           3'b001:MemWriteD=4'b0011;    //SH
           3'b010:MemWriteD=4'b1111;    //SW
           default:MemWriteD=4'b0000;
        endcase
    else
        MemWriteD=4'b0000;
end
//LoadNpcD
assign LoadNpcD=(JalD|JalrD)?1'b1:1'b0;                //只有Jal指令和Jalr指令时会计算PC+4并存入Reg[Rd]
//BranchTypeD
always_comb
begin
    if(Op==7'b1100011)                     //如果是B型指令(条件分支)
        case(Fn3)
           3'b000:BranchTypeD=BEQ;     //BEQ
           3'b001:BranchTypeD=BNE;     //BNE
           3'b100:BranchTypeD=BLT;     //BLT
           3'b101:BranchTypeD=BGE;     //BGE
           3'b110:BranchTypeD=BLTU;     //BLTU
           3'b111:BranchTypeD=BGEU;     //BGEU
           default:BranchTypeD=NOBRANCH;
        endcase
    else
        BranchTypeD=NOBRANCH;
end
//AluControlD
always_comb
begin
    case(Op)
        7'b0000011:AluControlD=ADD;       //LOAD指令,计算地址,ADD
        7'b0100011:AluControlD=ADD;       //STORE指令，计算地址，ADD
        7'b0110111:AluControlD=LUI;       //LUI指令，保持立即数不变
        7'b0010111:AluControlD=ADD;       //AUIPC指令，Reg[rs1]+Imm,ADD
        7'b1100011:AluControlD=ADD;       //B型条件分支指令，不使用ALU，dont care(分支跳转地址计算在ID阶段完成)
        7'b1101111:AluControlD=ADD;       //jal指令，未用到ALU(地址计算在ID阶段完成)
        7'b1100111:AluControlD=ADD;       //jalr指令，计算跳转地址(Reg[rs1]+Imm)&~1，ADD
        7'b0110011:                         //R型指令
        begin
            case(Fn3)
                3'b000:if(Fn7[5]==0)
                           AluControlD=ADD;
                       else
                           AluControlD=SUB;
                3'b001:AluControlD=SLL;
                3'b010:AluControlD=SLT;
                3'b011:AluControlD=SLTU;
                3'b100:AluControlD=XOR;
                3'b101:if(Fn7[5]==0)
                           AluControlD=SRL;
                       else
                           AluControlD=SRA;
                3'b110:AluControlD=OR;
                3'b111:AluControlD=AND;
                default:AluControlD=ADD;
            endcase
        end
        7'b0010011:                         //I型指令（寄存器-立即数和移位指令）
        begin
            case(Fn3)
                3'b000:AluControlD=ADD;
                3'b010:AluControlD=SLT;
                3'b011:AluControlD=SLTU;
                3'b100:AluControlD=XOR;
                3'b110:AluControlD=OR;
                3'b111:AluControlD=AND;
                3'b001:AluControlD=SLL;
                3'b101:if(Fn7[5]==0)
                            AluControlD=SRL;
                       else
                            AluControlD=SRA;
                default:AluControlD=ADD;
            endcase
        end
        default:AluControlD=ADD;
    endcase
end

//AluSrc1D,PC or 寄存器rs1
always_comb
if(Op==7'b0010111)                   //AUIPC指令，第一个源操作数来自PC
    AluSrc1D=1;
else
    AluSrc1D=0;
//AluSrc2D
always_comb
begin
    if(Op==7'b0010011&&(Fn3==3'b001||Fn3==3'b101))                  //移位指令
        AluSrc2D=2'b00;                  //来自rs2
    else if(Op==7'b1100011||Op==7'b0110011)           //R型指令或者B型指令
        AluSrc2D=2'b01;                 //来自Reg[rs2]
    else                                //其他指令
        AluSrc2D=2'b10;                 //来自立即数
end
//ImmTypeD
always_comb
begin
    case(Op)
        7'b0110011:ImmType=RTYPE;
        7'b0010011:ImmType=ITYPE;
        7'b0000011:ImmType=ITYPE;
        7'b1100111:ImmType=ITYPE;
        7'b1100011:ImmType=BTYPE;
        7'b0100011:ImmType=STYPE;
        7'b1101111:ImmType=JTYPE;
        7'b0110111:ImmType=UTYPE;
        7'b0010111:ImmType=UTYPE;
        default:ImmType=RTYPE;
    endcase
end

endmodule
